home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Experimental BBS Explossion 3
/
Experimental BBS Explossion III.iso
/
compress
/
acmp_300.zip
/
DCCMP.C
< prev
next >
Wrap
Text File
|
1991-02-17
|
37KB
|
1,133 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <process.h>
#include <errno.h>
#include <dos.h>
#include <sys\types.h>
#include <sys\stat.h>
#define VERSION "1.02" /* Version of this code */
#define START 0L
#define HOURS 1
#define MINS 2
#define ERROR -1L /* If a program in batch had an error */
#define COMMENT -2L /* If this line is a comment header */
#define DSIZE 300
#define INSZ 256
#define PATHSZ 100
#define PATSZ 50
#define LABSZ 50
char *norm(char *file);
int compare();
void getpath(char *cur);
void setpath(char *s);
long ticks(long op);
char *ticks2str(long ticks, short frmt);
char *dosfind(char *file);
static char *sort; /* Current sort order, for compare() */
typedef struct { /* Data array (one per executable line) */
char *file; /* ... Name of file to check size of */
char *des; /* ... Descriptive message to display */
char *name; /* ... Name of program to execute */
char *cmdln; /* ... Command line to pass to program */
char *err; /* ... Error message if any occur */
long tm; /* ... Clock ticks elasped on execution */
long size; /* ... Size in bytes of 'file' */
short display; /* ... TRUE, if data should be displayed */
} EXLINE;
/*
** NAME
** DCCMP -- Dean Cooper's comparer program, Version 1.02
**
** (C) Copyright 1989,1991 by Dean W. Cooper; All rights reserved
**
** The DCCMP program and its source code is FREE for both private and
** commercial uses, and may be freely distributed as long as it is NOT
** sold for profit. Please direct all correspondence to:
**
** Dean W. Cooper
** 3078 N Palo Verde
** Tucson, AZ 85716
** (602) 326-2403 (voice)
** (516) 536-8723 Sound-of-Music BBS
**
**
** DESCRIPTION
** DCCMP was written as a utility to do a comparison of archiver
** programs. However, it is really a fairly general comparison program.
** It works in a manner similar to batch interpreters in that is simply
** reads and executes lines from a text file one at a time. The usage
** for the program is as follows:
**
** DCCMP [-#] [-q] [-tsn] [-o<file>] <batch_file> [<arg1> <arg2> ...]
**
** -# Number of times to execute batch file (1<=#<=9)
** -q Quiet mode. Forces 'echo off' for all of batch file.
** -tsn Sort flags. Each flag generates a separate output:
** t ... Sorted by time of execution
** s ... Sorted by size of resulting file
** n ... No sort
** -k<number> Amount of memory to run programs in (x 1024)
** -z<arg0> Set value of 'arg0', normally arg0=<current directory>
** -o<file> Name of file to write output data to
** -a<file> Name of file to append output data to
** <batch_file> Name of batch file to execute (assumes ".CMP")
** <argN> Arguments to pass on to batch interpreter
** (If no args are given, then the batch file's
** usage information will be displayed.)
**
** DCCMP reads the specified batch file which should be in the current
** directory or in the directory specified by the environment variable
** "DCCMP" (current directory searched first). A batch file has the
** following format:
**
** [<filename>] [;] [<description> ;] <program> [command line args]
**
** -- Blank lines and lines preceded with '#' will be ignored.
**
** -- Lines preceded with ':' will be displayed as the batch file's
** usage information.
**
** -- Lines preceded with '>' will be displayed as a header to the
** output data.
**
** -- DCCMP substitutes occurrences of '%1' with <arg1>, '%2' with
** <arg2>, etc.
**
** -- Occurrences of '%0' are replaced with the current directory.
**
** -- If the line has no ';', then the program is simply executed.
**
** -- If the line has a ';', then the speed of the program's execution
** is timed and later displayed.
**
** -- If the line has <filename> defined, then the size of the
** specified file is recorded (after the program is executed) and
** later displayed.
**
** -- If the line has <description> defined, then that string will
** displayed when the statistical data is output (else the
** command line string will be used instead).
**
** -- If a line is of the form: '! label1 label2' then the output
** will be split into two parts (those lines with <filename> defined,
** and the those without), and labeled with the the specified labels.
**
** -- <program> can be one of the following:
**
** DEL <file1>..<fileN> Deletes files without the annoying
** "Are you sure?" prompt.
**
** PUSH <full_path> Save the current directory, and make the
** specified drive and directory current.
**
** POP Restore the last current directory.
**
** ECHO off Turn off echoing of programs.
** ECHO on Turn on echoing of programs.
** ECHO <text> Echo specified text to screen.
**
** SUBNXT "str1" "str2" Substitute on the next line only,
** occurances of 'str1' with 'str2'.
**
** HISTORY
** 2/21/89 DWC - Created
*/
main(argc, argv)
int argc;
char *argv[];
{
static EXLINE d[ DSIZE ]; /* Array of executable line data */
static char in[ INSZ ]; /* Buffer to read a batch file line in to */
static char sub[ INSZ ]; /* Buffer to do substitutions into */
static char tmp[ INSZ ]; /* Temporary buffer for strings */
static char dfile[ PATHSZ ]; /* Name of batch file to execute */
static char dir[5][ PATHSZ ]; /* Stack of current directories */
static char pat[ PATSZ ]; /* Buffer to hold substitution pattern */
static char rep[ PATSZ ]; /* Buffer to hold pattern's replacement */
static char *sorts[10]; /* Pointer to each sort to be generated */
static char label1[ LABSZ ]; /* Label one from a '!' line */
static char label2[ LABSZ ]; /* Label two from a '!' line */
short numsorts=0; /* Number of sorts defined */
FILE *f; /* File stream for batch file */
FILE *fo=stdout; /* File stream for output data */
short tms=1; /* Number of times to execute batch file */
short frst=2; /* Argument substituted for '%1' */
short lvl=0; /* Stack level */
short dsplusage=0; /* TRUE, if displaying batch file usage */
short quiet=0; /* TRUE, if not echoing all lines */
short noecho=0; /* TRUE, if not in echo mode */
short split=1; /* 2, if output being split into two parts*/
short sortsz; /* TRUE, if sorting output by size */
short numt=0; /* Number of 't' sort flags encountered */
short nums=0; /* Number of 's' sort flags encountered */
short numn=0; /* Number of 'n' sort flags encountered */
short kmem=0; /* K of memory to run programs in */
short actual=0; /* Actual amount of memory for programs */
char huge *mem; /* Pointer to memory eaten */
long tm_one; /* Time to run one program */
long tm_run; /* Time into current run of batch */
long tm_entire; /* Time of all runs */
long tm_perrun; /* Time to go through batch file one time */
char *white = " \t"; /* All characters considered white space */
char *empty = ""; /* The empty string */
char *arg0 = NULL; /* Pointer to value of 'arg0' */
char *s, *s1, *s2, *s3, *s4, c;
short i, j, k, m, num, p, q, rtn;
float rel;
long base;
struct stat buff;
/*
** Parse any options on command line.
*/
for (i=1 ; i<argc ; i++)
if (argv[i][0] != '-')
break;
else
for (j=1 ; c = argv[i][j] ; j++)
switch (c = tolower(c)) {
case 'q': quiet=1; break;
case 't':
if (numt++) break;
sorts[ numsorts++ ] = "ts";
break;
case 's':
if (nums++) break;
sorts[ numsorts++ ] = "st";
break;
case 'n':
if (numn++) break;
sorts[ numsorts++ ] = "n";
break;
case 'k':
kmem = atoi( &argv[i][j+1] );
for ( ; c = argv[i][j+1] ; j++)
if (c<'0' || c>'9')
break;
break;
case 'z':
arg0 = &argv[i][j+1];
j = strlen(argv[i]) - 1;
break;
case 'o':
if (!(fo = fopen(s = &argv[i][j+1], "w")))
printf("ERROR: Could not open output file: %s\n", s), exit(1);
j = strlen(argv[i]) - 1;
break;
case 'a':
if (!(fo = fopen(s = &argv[i][j+1], "a")))
printf("ERROR: Could not open output file: %s\n", s), exit(1);
j = strlen(argv[i]) - 1;
break;
default:
if ((k=c-'0') >=1 && k<=9) tms = k;
else usage();
}
frst = i+1;
if (i>=argc) usage();
/*
** If batch file name has no extension, put ".CMP" on.
*/
s = strupr( strcpy(dfile,argv[frst-1]) );
if (!strrchr(s,'.'))
strcat(s, ".CMP");
/*
** Open batch file.
*/
if (!(f = fopen(s, "r")))
if (s = getenv("DCCMP")) {
strcpy(in,dfile);
strcpy(dfile,s);
if (s[strlen(s)-1]!='\\') strcat(dfile, "\\");
strcat(dfile,in);
f = fopen(dfile, "r");
}
if (!f)
printf("ERROR: Cannot open batch file: %s\n", dfile), exit(1);
/*
** Save current directory.
*/
getpath( dir[lvl] );
if (!arg0) arg0 = dir[lvl];
/*
** Set flag if we're to display the batch file's usage.
*/
dsplusage = argc==frst;
/*
** Read in one line at a time from data file.
*/
for (j=0 ; j<DSIZE && fgets(in, INSZ, f) ; ) {
/*
** Remove trailing newline (if any).
*/
if (in[i=strlen(in)-1]=='\n') in[i]=0;
/*
** If just display batch file's usage, then do it.
*/
if (dsplusage)
if (in[0]==':') puts(in+1);
else continue;
/*
** Skip comment lines and blank lines.
*/
if (in[0]=='#' || in[0]==':' || !in[0])
continue;
/*
** See if this is a command line to split output into two parts.
*/
if (in[0]=='!') {
split = 2;
if (s = strtok(in+1, white)) {
strcpy(label1, s);
if (s = strtok(NULL, white))
strcpy(label2, s);
}
continue;
}
/*
** Clear the entry for this line.
*/
d[j].file = d[j].name = d[j].des = d[j].cmdln = empty;
d[j].file[0] = d[j].name[0] = d[j].des[0] = d[j].cmdln[0] = d[j].size = d[j].tm = d[j].display = 0;
/*
** Expand occurances of '%0', '%1', etc, into arguments from command line.
*/
for (s=strcpy(sub,in) ; s = strchr(s, '%') ; strcpy(in,sub))
if (!( (i = s[1]-'0') >=0 && i<=9 ))
s++;
else
if (i == 0) strcpy(s, arg0), strcat(s, in+(s-sub)+2);
else if (i>argc-frst) strcpy(s, in+(s-sub)+2);
else strcpy(s, argv[i+frst-1]), strcat(s, in+(s-sub)+2);
/*
** See if line is a output header comment line.
*/
if (in[0]=='>') {
d[j].cmdln = strdup(in+1); d[j++].size= COMMENT; continue; }
/*
** Get copy of file name part of line.
*/
if (!(s = strchr(in, ';'))) s=in-1;
else {
d[j].display = 1;
if (*(in + strspn(in," \t")) != ';')
d[j].file = strdup( strtok(strcpy(sub,in), " \t;") );
}
strcpy(sub, s+1);
strcpy(in, sub);
/*
** Get copy of description part of line.
*/
if (!(s = strchr(in, ';'))) s=in-1;
else {
if (*(s1 = in + strspn(in," \t")) != ';')
strncpy(tmp, s1, s-s1), tmp[ s-s1 ]=0, d[j].des=strdup(tmp);
}
strcpy(sub, s+1);
/*
** Get copy of program name part and command line part of line.
*/
if (s = strtok(strcpy(in,sub), white)) d[j].name = strdup(s);
else continue;
strupr(d[j].name);
if (s = strtok(NULL, white)) { /* We now know there is a cmd line */
s = sub + strspn(sub,white); /* ... Skip white space before name*/
s = strpbrk(s, white); /* ... Skip over program name */
if (strcmp(d[j].name, "ECHO"))
s = s + strspn(s, white); /* ... Skip white space after name */
d[j].cmdln = strdup(s);
}
j++;
}
fclose(f);
if (dsplusage)
exit(0);
/*
** See if there was any allocation errors.
*/
for (num=j, j=0 ; j<num ; j++)
if (!d[j].file || !d[j].name || !d[j].cmdln || !d[j].des)
printf("ERROR: Out of memory.\n"), exit(1);
/*
** Reduce amount of memory that programs have to run in.
*/
if (kmem) {
for (i=600 ; i>1 && (mem = halloc((long) i,1024)) == NULL ; i--);
hfree(mem);
if (i>kmem)
if (!(mem = halloc((long) (i-kmem), 1024)))
printf("ERROR: Huge memory allocation error.\n"), exit(1);
}
for (i=600 ; i>1 && (mem = halloc((long) i,1024)) == NULL ; i--);
actual = i;
hfree(mem);
/*
** Start clock on entire run of batch.
*/
tm_entire = tm_run = ticks(START);
/*
** Run through again and execute programs.
*/
for (i=0 ; i<tms ; i++) {
if (i) tm_run = ticks(START);
for (m=j=0 ; j<num ; j++)
if (d[j].size>=0) {
s = d[j].name;
strcpy(in, d[j].cmdln);
/*
** Execute echo command before any commands are 'echoed'.
*/
if (!strcmp(s, "ECHO")) {
s = strupr(strtok(in,white));
if (!strcmp(s, "OFF")) noecho = 1;
else if (!strcmp(s, "ON")) noecho = 0;
else
printf("%s\n", d[j].cmdln);
continue;
}
/*
** If not in quite mode, display program we're executing.
*/
if (!quiet && !noecho) {
printf("\nRun: %d Line: %2d Time elapsed: %7s Time to go: ", i+1, ++m, ticks2str(ticks(tm_entire), HOURS));
if (!i) printf("Unknown\n");
else printf("%7s\n", ticks2str(tm_perrun * (tms-i-1) + tm_perrun - ticks(tm_run), HOURS) );
printf("[ %s ] %s %s\n", dir[lvl], norm(d[j].name), d[j].cmdln);
}
/*
** Execute internally defined commands.
*/
if (!strcmp(s, "PUSH")) {
setpath( strtok(in, white) );
getpath( dir[++lvl] );
continue;
}
else if (!strcmp(s, "POP")) {
if (lvl>0)
setpath( dir[--lvl] ), getpath( dir[lvl] );
continue;
}
else if (!strcmp(s, "DEL")) {
s = strtok(in, white);
do {
if (s = dosfind(s))
while (s)
remove(s), s=dosfind(NULL);
} while (s = strtok(NULL, white));
continue;
}
/*
** Do pattern substition on following line's command line.
*/
else if (!strcmp(s, "SUBNXT")) {
s = d[j].cmdln;
if ((s1 = strchr(s, '"')) && (s2 = strchr(s1+1, '"')) &&
(s3 = strchr(s2+1, '"')) && (s4 = strchr(s3+1, '"')) && j+1<num) {
/*
** Get pattern to search for and it's replacement.
*/
strncpy(pat, s1+1, (s2-s1)-1), pat[ (s2-s1)-1 ] = 0;
strncpy(rep, s3+1, (s4-s3)-1), rep[ (s4-s3)-1 ] = 0;
s = d[j+1].cmdln;
k = strlen(pat);
/*
** Now do the substition.
*/
if (pat[0])
for (s1=strcpy(sub,s) ; s1 = strchr(s1, pat[0]) ; strcpy(s,sub))
if (!strncmp(s1, pat, k))
strcpy(s1, rep), strcat(s1, s+(s1-sub)+k);
else
s1++;
}
continue;
}
/*
** Execute and time regular DOS program.
*/
tm_one = ticks(START);
if (rtn = spawnlp(P_WAIT, d[j].name, d[j].name, d[j].cmdln, NULL)) {
if (rtn != -1)
printf("ERROR: Program returned error value of: %d\n", rtn);
else if (errno == E2BIG) printf("ERROR: Command line <%s> too long.\n", d[j].cmdln);
else if (errno == ENOENT) printf("ERROR: Program not found: <%s>\n", norm(d[j].name));
else if (errno == ENOEXEC) printf("ERROR: Invalid executable format: <%s>\n", norm(d[j].name));
else if (errno == ENOMEM) printf("ERROR: Not enough memory to run: <%s>\n", norm(d[j].name));
if (rtn != -1)
sprintf(tmp, "ERROR: Exit value of: %d", rtn), d[j].err=strdup(tmp);
else if (errno == E2BIG) d[j].err = "ERROR: Command line too long";
else if (errno == ENOENT) d[j].err = "ERROR: Program not found";
else if (errno == ENOEXEC) d[j].err = "ERROR: Invalid EXE file";
else if (errno == ENOMEM) d[j].err = "ERROR: Not enough memory";
d[j].size = ERROR;
continue;
}
d[j].tm += ticks(tm_one);
/*
** Record resulting file size if it was specified.
*/
if (d[j].file[0]) {
if (stat(d[j].file,&buff)) {
printf("ERROR: File not found: <%s>\n", d[j].file);
d[j].err = "ERROR: File was not found";
d[j].size = ERROR;
continue;
}
d[j].size += buff.st_size;
}
}
tm_perrun = ticks(tm_entire)/(i+1);
}
/*
** Calculate total time elasped.
*/
tm_entire = ticks(tm_entire);
tm_perrun = tm_entire/tms;
/*
** Display header for output of data.
*/
fprintf(fo, "\n\n\n------------------------------------------------------------------------------\n");
fprintf(fo, "This output was generated by:\n");
fprintf(fo, "DCCMP - Dean Cooper's comparer program, Version %s\n\n", VERSION);
fprintf(fo, "DCCMP was run as: \"DCCMP");
for (i=1 ; i<argc ; i++)
fprintf(fo, " %s", argv[i]);
fprintf(fo,"\"\n\n Batch %8s was run: %7d time%s...\n", strupr(argv[frst-1]), tms, tms>1 ? "s" : "");
fprintf(fo, "Memory free for programs: %7d K\n", actual);
fprintf(fo, " Time per run: %7s\n", ticks2str(tm_perrun, HOURS));
fprintf(fo, " Total time elapsed: %7s\n", ticks2str(tm_entire, HOURS));
/*
** Display header comment lines (if any).
*/
for (j=0 ; j<num ; j++)
if (d[j].size == COMMENT)
fprintf(fo, "%s\n", d[j].cmdln);
/*
** Run through again and display results. If split==2, then we are
** separating the output of those lines with file sizes, from those
** without. Also, we display once for each requested sort.
*/
for (k=0 ; k<split ; k++)
for (i=0 ; i<numsorts || i<1 ; i++) {
s = k==0 ? label1 : label2;
/*
** Sort data if any sort is asked for.
*/
if (numsorts) {
sort = strlwr( sorts[i] );
qsort(&d[0], num, sizeof(d[0]), compare);
}
/*
** Display data if sorting by size or speed.
*/
if (numsorts && sort[0]!='n') {
sortsz = sort[0]=='s';
if (k==1 && sortsz && numsorts>1)
continue;
if (s[0]) fprintf(fo, "\n\n%s, s", s);
else fprintf(fo, "\n\nS");
fprintf(fo, "orted by: %s", sortsz && (split<2 || k==0) ? "Size" : "Speed");
fprintf(fo, "\n\nProgram Description Ticks Min:Secs %s%s\n", (split<2 || k==0) ? "Size " : "", (split>1 && sortsz && k==1) ? "" : "Relative");
fprintf(fo, "======== ====================== ====== ======== %s%s\n", (split<2 || k==0) ? "======== " : "", (split>1 && sortsz && k==1) ? "" : "========");
for (m=j=0 ; j<num ; j++)
if (d[j].size>=ERROR && d[j].display) {
s = d[j].des[0] ? d[j].des : d[j].cmdln;
p = d[j].size >0 && (split<2 || k==0);
q = d[j].size<=0 && (split<2 || k==1);
if (d[j].size==ERROR && (p || q)) {
fprintf(fo, "%-8s %-22s %s\n", norm(d[j].name), s, d[j].err); continue; }
if (sortsz && q)
fprintf(fo, "%-8s %-22s %6ld %8s\n", norm(d[j].name), s, d[j].tm/tms, ticks2str(d[j].tm/tms, MINS));
else {
if (p || q) {
if (!m++)
base = sortsz ? d[j].size : d[j].tm;
if (sortsz) rel = ((float) d[j].size)/base;
else rel = ((float) d[j].tm )/base;
}
if (p) fprintf(fo, "%-8s %-22s %6ld %8s %8ld %8.2f\n", norm(d[j].name), s, d[j].tm/tms, ticks2str(d[j].tm/tms, MINS), d[j].size/tms, rel);
if (q) fprintf(fo, "%-8s %-22s %6ld %8s %s%8.2f\n", norm(d[j].name), s, d[j].tm/tms, ticks2str(d[j].tm/tms, MINS), split<2 ? " " : "", rel);
}
}
}
else {
/*
** Display data if Not sorting.
*/
if (s[0]) fprintf(fo, "\n\n%s%s:", s, numsorts ? ", not sorted" : "");
else if (numsorts) fprintf(fo, "\n\nNot sorted:");
fprintf(fo, "\n\nProgram Description Ticks Min:Secs%s\n", (split<2 || k==0) ? " Size " : "");
fprintf(fo, "======== ====================== ====== ========%s\n", (split<2 || k==0) ? " ======== " : "");
for (j=0 ; j<num ; j++)
if (d[j].size>=ERROR && d[j].display) {
s = d[j].des[0] ? d[j].des : d[j].cmdln;
p = d[j].size >0 && (split<2 || k==0);
q = d[j].size<=0 && (split<2 || k==1);
if (d[j].size==ERROR && (p || q)) {
fprintf(fo, "%-8s %-22s %s\n", norm(d[j].name), s, d[j].err); continue; }
if (p) fprintf(fo, "%-8s %-22s %6ld %8s %8ld\n", norm(d[j].name), s, d[j].tm/tms, ticks2str(d[j].tm/tms, MINS), d[j].size/tms);
if (q) fprintf(fo, "%-8s %-22s %6ld %8s\n", norm(d[j].name), s, d[j].tm/tms, ticks2str(d[j].tm/tms, MINS));
}
}
}
exit(0);
}
usage()
{
printf("DCCMP - Dean Cooper's comparer program, Version %s\n", VERSION);
printf("(C) Copyright 1989,1991 by Dean W. Cooper; All right reserved\n\n");
printf("The DCCMP program and its source code is FREE for both private and commercial\n");
printf("uses, and may be freely distributed as long as it is NOT sold for profit.\n");
printf("Please direct all correspondence to:\n\n");
printf(" Dean W. Cooper\n");
printf(" 3078 N Palo Verde\n");
printf(" Tucson, AZ 85716\n");
printf(" (602) 326-2403 (voice)\n");
printf(" (516) 536-8723 Sound-of-Music BBS\n");
printf("\n <hit any key>");
getch();
printf("\n\n\nDCCMP lets one compare programs by the speed of their execution, and\n");
printf("by the size of the file they produce. DCCMP works in a manner similar\n");
printf("to batch interpreters in that it simply reads and executes lines from\n");
printf("a text file one at a time. The usage is:\n\n");
printf(" DCCMP [-#] [-q] [-tsn] [-o<file>] <batch_file> [<arg1> <arg2>...]\n\n");
printf(" -# Number of times to execute batch file (1<=#<=9)\n");
printf(" -q Quiet mode. Forces 'echo off' for all of batch file.\n");
printf(" -tsn Sort flags. Each flag generates a separate output:\n");
printf(" t ... Sorted by Time of execution\n");
printf(" s ... Sorted by Size of resulting file\n");
printf(" n ... No sort\n");
printf(" -k<number> Amount of memory to run programs in (x 1024)\n");
printf(" -z<arg0> Set value of 'arg0', normally arg0=<current directory>\n");
printf(" -o<file> Name of file to write output data to\n");
printf(" -a<file> Name of file to append output data to\n");
printf(" <batch_file> Name of batch file to execute (assumes \".CMP\")\n");
printf(" <argN> Arguments to pass on to batch interpreter\n");
printf(" (If no args are given, then the batch file's\n");
printf(" usage information will be displayed.)\n");
printf("\n <hit any key>");
getch();
printf("\n\n\n\n\nDCCMP reads the specified batch file which should be in the current\n");
printf("directory or in the directory specified by the environment variable\n");
printf("\"DCCMP\" (current directory searched first).\n\n");
printf(" A batch file has the following format:\n\n");
printf(" [filename] [;] [<description> ;] <program> [command line args]\n\n");
printf(" -- Blank lines and lines preceded with '#' will be ignored.\n");
printf(" -- Lines preceded with ':' will be displayed as the batch file's\n");
printf(" usage information.\n");
printf(" -- Lines preceded with '>' will be displayed as a header to the\n");
printf(" output data.\n");
printf(" -- DCCMP substitutes occurrences of '%%1' with <arg1>, '%%2' with\n");
printf(" <arg2>, etc.\n");
printf(" -- Occurrences of '%%0' are replaced with the current directory.\n");
printf(" -- If the line has no ';', then the program is simply executed.\n");
printf(" -- If the line has a ';', then the speed of the program's execution\n");
printf(" is timed and later displayed.\n");
printf(" -- If the line has <filename> defined, then the size of the\n");
printf(" specified file is recorded (after the program is executed) and\n");
printf(" later displayed.\n");
printf("\n <hit any key>");
getch();
printf("\n\n\n\n\n\n -- If the line has <description> defined, then that string will\n");
printf(" displayed when the statistical data is output (else the\n");
printf(" command line string will be used instead).\n");
printf(" -- If a line is of the form: '! label1 label2' then the output\n");
printf(" will be split into two parts (those lines with <filename> defined,\n");
printf(" and the those without), and labeled with the the specified labels.\n\n");
printf(" The following are internally defined programs:\n\n");
printf(" DEL <file1>..<fileN> Deletes files without the annoying\n");
printf(" \"Are you sure?\" prompt.\n");
printf(" PUSH <full_path> Save the current directory, and make the\n");
printf(" specified drive and directory current.\n");
printf(" ECHO off Turn off echoing of programs.\n");
printf(" ECHO on Turn on echoing of programs.\n");
printf(" ECHO <text> Echo specified text to screen.\n");
printf(" POP Restore the last current directory.\n");
printf(" SUBNXT \"str1\" \"str2\" Substitute on the next line only,\n");
printf(" occurances of 'str1' with 'str2'.\n");
exit(2);
}
/*
** NAME
** norm -- Return pointer to normal part of filename
*/
char *norm(char *file)
{
int i;
for (i=strlen(file)-1 ; i>=0 ; i--)
if (file[i]=='\\' || file[i]==':')
break;
return &file[i+1];
}
/*
** NAME
** compare -- This function is called by the 'qsort' routine
*/
int compare(e1, e2)
EXLINE *e1, *e2;
{
short i, j=0;
char c;
long l;
for (i=0 ; (c=tolower(sort[i])) && !j ; i++)
if (c == 't') j = (int) (l = e1->tm - e2->tm, (l<0 ? -1 : (l>0 ? 1 : 0)));
else if (c == 's') j = (int) (l = e1->size - e2->size, (l<0 ? -1 : (l>0 ? 1 : 0)));
else if (c == 'n') j = e1>e2 ? 1 : (e1<e2 ? -1 : 0);
return j;
}
/*
** NAME
** getpath -- Get current drive and path
**
** SYNOPSIS
** void getpath( s );
**
** char *s; -- Pointer to where to put current drive and path
**
** DESCRIPTION
** This function simply returns DOS's currently logged drive and path.
** The return string will be terminated with a slash: '\'.
*/
void getpath(cur)
char *cur;
{
getcwd(cur, 80);
strupr(cur);
if (cur[strlen(cur)-1] != '\\') strcat(cur, "\\");
}
/*
** NAME
** setpath -- Set current drive and path
**
** SYNOPSIS
** void setpath( s );
**
** char *s; -- Pointer drive and directory to set
**
** DESCRIPTION
** This function simply sets current the specified drive and directory.
*/
void setpath(s)
char *s;
{
short k;
k=strlen(s) - 1;
if (k<0 || s[k]==':') strcat(s, "\\");
else if (s[k]=='\\' && k>0) s[k]=0;
if (s[1]==':')
bdos(0x0E, toupper(s[0]) - 'A', 0);
chdir(s);
}
/*
** NAME
** ticks -- Return current time or number of ticks that have elapsed
**
** SYNOPSIS
** long ticks( op );
**
** long op; -- START, to return current time
** last_time, to return elapsed ticks since 'last_time'
**
** DESCRIPTION
** When this function is called with START, it returns the current time.
** Then when the function is called with a 'time', it returns the number
** of ticks that have elapsed since that 'time'.
*/
long ticks(op)
long op;
{
static unsigned long last=0L, overflow=0L;
unsigned long cur;
union REGS regs;
regs.x.ax = 0;
int86(0x1A, ®s, ®s);
cur = regs.x.dx;
cur |= ((unsigned long) regs.x.cx) << 16;
if (cur < last) overflow+=1573039L;
last = cur;
cur += overflow;
if (op!=START) cur = cur - op;
return (long) cur;
}
/*
** NAME
** ticks2str -- Convert number of ticks to string with hours/minutes/secs
**
** SYNOPSIS
** char *ticks2str( ticks, format );
**
** long ticks; -- Number of ticks
** short format; -- HOURS, for string in "hh:mm:ss" format
** MINS, for string in "mmm:ss.t" format
**
** DESCRIPTION
** This function converts the number of ticks to a string with hours,
** minutes, and seconds (8 characters long).
*/
char *ticks2str(ticks, frmt)
long ticks;
short frmt;
{
static char str[10];
short hours, min;
float secs;
secs = ticks / 18.2;
min = secs / 60;
hours = min / 60;
if (frmt == MINS) {
secs = ticks / 18.2 - min * 60;
sprintf(str, "%03d:%04.1f", min, secs);
}
else {
secs = secs - min * 60;
min = min - hours * 60;
sprintf(str, "%d:%02d:%02d", hours, min, (int) secs);
}
return str;
}
/*
** NAME
** dosfind -- Find first and next DOS files with wildcard expansion
**
** SYNOPSIS
** char *dosfind( file );
**
** char *file; -- Name of file (with wildcards) to match
** NULL, to return next match
**
** RETURNS
** char *match; -- Returns next file that matched
**
** DESCRIPTION
** This function does DOS wildcard expansion to find the first and
** next files that match the specified file spec (only 'normal' files
** are found).
*/
#define DIR_ATTR 0x10
#define SEGMENT(p) (*((unsigned short*)&(p)+1))
#define OFFSET(p) (*((unsigned short*)&(p)))
char *dosfind(file)
char *file;
{
static char org[ PATHSZ ];
static short i;
static struct {
char res[21];
char attr;
unsigned time;
unsigned date;
long size;
char name[13];
} dta, *p=&dta;
union REGS regs;
bdos(0x1a, OFFSET(p), 0); /* Set data transfer area (DTA) */
if (file) {
strcpy(org,file); /* Save file's path */
i = strlen(org); /* Find where path part of name ends */
for (i-- ; i>=0 && org[i]!='\\' && org[i]!=':' ; i--);
i++;
regs.h.ah = 0x4e; /* Search for first match */
regs.x.cx = 0x00; /* Get normal files only */
regs.x.dx = OFFSET(file); /* Search string */
}
else
regs.h.ah = 0x4f; /* Search for next match */
intdos(®s, ®s);
if (regs.x.cflag) /* If NO match return NULL */
return NULL;
strcpy(org+i, dta.name); /* Else, tack name onto file path */
return org; /* And return pointer to full name */
}